package cn.jbolt.core.service;

import cn.hutool.core.util.IdUtil;
import cn.jbolt.core.api.JBoltApiJwtManger;
import cn.jbolt.core.api.JBoltApiKit;
import cn.jbolt.core.api.JBoltApiUserBean;
import cn.jbolt.core.base.JBoltMsg;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.cache.JBoltApplicationCache;
import cn.jbolt.core.cache.JBoltGlobalConfigCache;
import cn.jbolt.core.cache.JBoltOnlineUserCache;
import cn.jbolt.core.common.enums.JBoltUserOnlineState;
import cn.jbolt.core.db.sql.Sql;
import cn.jbolt.core.kit.JBoltSaasTenant;
import cn.jbolt.core.kit.JBoltSaasTenantKit;
import cn.jbolt.core.kit.JBoltSnowflakeKit;
import cn.jbolt.core.kit.JBoltUserKit;
import cn.jbolt.core.model.Application;
import cn.jbolt.core.model.LoginLog;
import cn.jbolt.core.model.OnlineUser;
import cn.jbolt.core.model.User;
import cn.jbolt.core.service.base.JBoltBaseService;
import cn.jbolt.core.util.JBoltDateUtil;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Okv;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Page;
import net.dreamlu.event.EventKit;

import java.time.Duration;
import java.util.Date;
import java.util.List;

/**
 * 在线用户
 *
 * @ClassName: OnlineUserService
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2021年2月23日
 *
 *        注意：本内容仅限于JFinal学院 JBolt平台VIP成员内部传阅，请尊重开发者劳动成果，不要外泄出去用于其它商业目的
 */
public class JBoltOnlineUserService extends JBoltBaseService<OnlineUser> {
	protected OnlineUser dao = new OnlineUser().dao();
	@Inject
	protected JBoltUserService jboltUserService;

	@Override
	protected OnlineUser dao() {
		return dao;
	}
	public OnlineUser processUserLogin(User user, LoginLog log) {
		//boolean isLoginTerminalOnlyOne = JBoltGlobalConfigCache.me.isLoginTerminalOnlyOne();
		OnlineUser onlineUser = null;
		//if (isLoginTerminalOnlyOne) {
			//processAllSameUserOffline(user.getId());
		//}
		return saveOnlineUser(user, log);
	}

	/**
	 * 保存onlineUser信息
	 * @param user
	 * @param log
	 * @return
	 */
	private OnlineUser saveOnlineUser(User user, LoginLog log) {
		OnlineUser onlineUser=new OnlineUser();
		onlineUser.setSessionId(genNewSessionId());
		onlineUser.setUserId(user.getId());
		onlineUser.setLoginLogId(log.getId());
		onlineUser.setJboltJwt("nothing");
		onlineUser.setJboltRefreshJwt("nothing");
		onlineUser.setLoginTime(user.getLoginTime());
		onlineUser.setScreenLocked(false);
		onlineUser.setOnlineState(JBoltUserOnlineState.ONLINE.getValue());
		int keepLoginSeconds = (int) (Duration.ofMillis(JBoltApiKit.getApplyJwtTTL()).getSeconds());
		onlineUser.setExpirationTime(JBoltDateUtil.getSecondsAfter(log.getLoginTime(), keepLoginSeconds));
		boolean success=onlineUser.save();
		if(!success){
			LOG.error("登录授权 执行新在线用户save异常");
		}
		return success?onlineUser:null;
	}

	/**
	 * 获取后台管理数据
	 *
	 * @param pageNumber
	 * @param pageSize
	 * @param keywords
	 * @param state
	 * @return
	 */
	public Page<OnlineUser> paginateAdminDatas(int pageNumber, int pageSize, String keywords, Integer state) {
		Sql sql = selectSql().page(pageNumber, pageSize);
		if (isOk(keywords)) {
			sql.from(table(), "ou");
			sql.leftJoin(jboltUserService.table(), "jbu", "jbu.id=ou.user_id");
			sql.likeMulti(keywords, "jbu.name", "jbu.username", "jbu.phone", "jbu.pinyin", "jbu.login_ip");
			sql.eqIfOk("ou.online_state", state);
			sql.orderBy("ou.update_time", true);
		} else {
			sql.eqIfOk("online_state", state);
			sql.orderBy("update_time", true);
		}
		return paginate(sql);
	}

	/**
	 * 异端顶替下线处理
	 *
	 * @param userId
	 */
	public void processAllSameUserOffline(Long userId) {
		Date now = new Date();
		Sql sql = selectSql().eqQM("user_id", "online_state");
		dao.each(ou -> {
			ou.setUpdateTime(now);
			ou.setOnlineState(JBoltUserOnlineState.TERMINAL_OFFLINE.getValue());
			ou.setOfflineTime(now);
			boolean success = ou.update();
			if (success) {
				EventKit.post(ou);
			}
			return true;
		}, sql.toSql(), userId, JBoltUserOnlineState.ONLINE.getValue());
	}

	/**
	 * 当前用户自行下线
	 */
	public void currentUserLogout() {
		OnlineUser onlineUser = JBoltUserKit.getOnlineUser();
		if (onlineUser != null) {
			onlineUser.setOnlineState(JBoltUserOnlineState.OFFLINE.getValue());
			Date nowDate = new Date();
			onlineUser.setOfflineTime(nowDate);
			onlineUser.setExpirationTime(nowDate);
			onlineUser.update();
		}
	}

	/**
	 * 生成一个sessionId
	 *
	 * @return
	 */
	public String genNewSessionId() {
		return IdUtil.fastSimpleUUID() + JBoltSnowflakeKit.me.nextIdStr();
	}

	/**
	 * 根据sessionId删除onlineUser
	 *
	 * @param oleSessionId
	 */
	public void deleteBySessionId(String oleSessionId) {
		dao().each(user -> {
			user.delete();
			return true;
		}, selectSql().eqQM("session_id").toSql(), oleSessionId);

	}

	/**
	 * 通过UserId获取 保证一个user 只有一个onlineUser
	 *
	 * @param userId
	 * @return
	 */
	public OnlineUser getByUserId(Long userId) {
		if (notOk(userId)) {
			return null;
		}
		return findFirst(Okv.by("user_id", userId));
	}

	/**
	 * 操作当前用户锁屏
	 *
	 * @return
	 */
	public Ret lockCurrentUserScreen() {
		OnlineUser onlineUser = JBoltUserKit.getOnlineUser();
		onlineUser.setScreenLocked(true);
		boolean success = onlineUser.update();
		return ret(success);
	}

	/**
	 * 操作当前用户解锁
	 *
	 * @return
	 */
	public Ret unlockCurrentUserScreen() {
		OnlineUser onlineUser = JBoltUserKit.getOnlineUser();
		onlineUser.setScreenLocked(false);
		boolean success = onlineUser.update();
		return ret(success);
	}

	/**
	 * 强退用户
	 *
	 * @param onlineUserId
	 * @return
	 */
	public Ret forcedOffline(Long onlineUserId) {
		if (!JBoltUserKit.isSystemAdmin()) {
			return fail("只有超管才有强退权限");
		}
		if (notOk(onlineUserId)) {
			return fail(JBoltMsg.PARAM_ERROR);
		}
		Long sessionUserId = JBoltUserKit.getUserId();
		if (notOk(sessionUserId)) {
			return fail("当前操作用户信息异常");
		}
		String currentUserSessionId = JBoltUserKit.getUserSessionId();
		if (notOk(currentUserSessionId)) {
			return fail("当前操作用户信息异常");
		}
		OnlineUser onlineUser = findById(onlineUserId);
		if (onlineUser == null) {
			return fail(JBoltMsg.DATA_NOT_EXIST);
		}
		User user = jboltUserService.findById(onlineUser.getUserId());
		if (user == null) {
			return fail("异常，被强退用户信息未找到");
		}
		if (currentUserSessionId.equals(onlineUser.getSessionId())) {
			// 如果当前用户和被操作强退是一个人 也就是自己强退自己 是不可以的
			return fail("自己不能强退自己");
		}

		if (user.getIsSystemAdmin()) {
			return fail("无法强退超管");
		}

		onlineUser.setOnlineState(JBoltUserOnlineState.FORCED_OFFLINE.getValue());
		Date nowDate = new Date();
		onlineUser.setOfflineTime(nowDate);
		boolean success = onlineUser.update();
		if (success) {
			EventKit.post(onlineUser);
		}
		return ret(success);
	}


	/**
	 * saas模式下 删除各个租户的jbonlineuser 该清理的清理掉
	 */
	public void deleteAllSaasTenantOfflineAndExpirationUser(){
		List<JBoltSaasTenant> saasTenants = JBoltSaasTenantKit.me.getAccessibleSaasTenants();
		if(notOk(saasTenants)){
			LOG.warn("尚未获取到有效的租户信息");
			return;
		}
		for(JBoltSaasTenant tenant:saasTenants){
			deleteTheSaasTenantOfflineAndExpirationUser(tenant);
		}
	}

	/**
	 * 删除指定一个租户的onlineuser过期信息
	 * @param tenant
	 */
	private void deleteTheSaasTenantOfflineAndExpirationUser(JBoltSaasTenant tenant) {
		JBoltSaasTenantKit.me.useById(tenant.getId()).call(this::deleteTheOfflineAndExpirationUser);
	}

	/**
	 * 清理离线用户信息
	 */
	public void deleteOfflineAndExpirationUser() {
		//saas模式删除完总部删租户 普通模式 直接删除系统默认
		if(JBoltConfig.SAAS_ENABLE){
			//删除完总部
			deleteTheOfflineAndExpirationUser();
			//删租户
			deleteAllSaasTenantOfflineAndExpirationUser();
		}else{
			deleteTheOfflineAndExpirationUser();
		}
	}

	/**
	 * 在线用户信息删除
	 */
	private void deleteTheOfflineAndExpirationUser() {
		//批量处理非在线用户缓存
		dao().each(ou -> {
			ou.deleteIdCache();
			ou.deleteKeyCache();
			JBoltOnlineUserCache.me.removeOnlineUserSessionListByUserId(ou.getUserId());
			return true;
		}, selectSql().select("id","session_id","user_id").notEqQM("online_state").toSql(), JBoltUserOnlineState.ONLINE.getValue());
		//批量删除当前非在线状态用户
		delete(deleteSql().notEqQM("online_state").toSql(), JBoltUserOnlineState.ONLINE.getValue());

		//批量处理过期用户缓存
		dao().each(ou -> {
			ou.deleteIdCache();
			ou.deleteKeyCache();
			JBoltOnlineUserCache.me.removeOnlineUserSessionListByUserId(ou.getUserId());
			return true;
		}, selectSql().select("id","session_id","user_id").eqQM("online_state")
				.le("expiration_time", toDateTime(JBoltDateUtil.format(new Date(), JBoltDateUtil.YMDHMS))).toSql(),
				JBoltUserOnlineState.ONLINE.getValue());
		//批量删除过期用户
		delete(deleteSql().eqQM("online_state")
						.le("expiration_time", toDateTime(JBoltDateUtil.format(new Date(), JBoltDateUtil.YMDHMS))).toSql(),
				JBoltUserOnlineState.ONLINE.getValue());
	}

	/**
	 * 获取指定用户的 在线token list
	 *
	 * @param userId
	 */
	public List<String> getSessionListByUserId(Long userId) {
		return query(selectSql().select("session_id").eq("user_id", userId).eq("online_state",
				JBoltUserOnlineState.ONLINE.getValue()));
	}

	/**
	 * 得到一个岗位的在线用户的session
	 *
	 * @param postId
	 * @return
	 */
	public List<String> getSessionListByPostId(Object postId) {
		Sql sql = selectSql().from(table(), "online").select("online.session_id").eq("online.online_state",
				JBoltUserOnlineState.ONLINE.getValue());
		sql.leftJoin(jboltUserService.table(), "u", "u.id =  online.user_id");
		sql.findInSet(postId, "u.posts", true);
		return query(sql);
	}

	/**
	 * 得到一个岗位的在线用户的session
	 *
	 * @param roleId
	 * @return
	 */
	public List<String> getSessionListByRoleId(Object roleId) {
		Sql sql = selectSql().from(table(), "online").select("online.session_id").eq("online.online_state",
				JBoltUserOnlineState.ONLINE.getValue());
		sql.leftJoin(jboltUserService.table(), "u", "u.id =  online.user_id");
		sql.findInSet(roleId, "u.roles", true);
		return query(sql);
	}

	/**
	 * 得到一个部门的在线用户的session
	 *
	 * @param deptId
	 * @return
	 */
	public List<String> getSessionListByDeptId(Object deptId) {
		Sql sql = selectSql().from(table(), "online").select("online.session_id").eq("online.online_state",
				JBoltUserOnlineState.ONLINE.getValue());
		sql.leftJoin(jboltUserService.table(), "u", "u.id =  online.user_id");
		sql.eq("u.dept_id", deptId);
		return query(sql);
	}

	@Override
	protected int systemLogTargetType() {
		return 0;
	}

	public void updateOnlineUserJwts(Long onlineUserId, String jboltJwt,String jboltRefreshJwt) {
		if(hasNotOk(onlineUserId,jboltJwt,jboltRefreshJwt)){
			throw new RuntimeException("updateOnlineUserJwts 失败 参数异常");
		}
		OnlineUser onlineUser = findById(onlineUserId);
		if(onlineUser == null){
			throw new RuntimeException("updateOnlineUserJwts 失败！");
		}
		onlineUser.setJboltJwt(jboltJwt);
		onlineUser.setJboltRefreshJwt(jboltRefreshJwt);
		boolean success = onlineUser.update();
		if(!success){
			throw new RuntimeException("updateOnlineUserJwts 更新失败！");
		}
	}

	/**
	 * 根据JWT 删除onlineUser
	 * @param jwt
	 * @param refreshJwt
	 */
	public void deleteByJwt(String jwt, boolean refreshJwt) {
		if(notOk(jwt)){
			throw new RuntimeException("用户授权令牌已过期，处理对应在线用户信息时异常：token 参数异常");
		}
		Sql sql= selectSql();
		if(refreshJwt){
			sql.eq("jbolt_refresh_jwt",jwt);
		}else{
			sql.eq("jbolt_jwt",jwt);
		}
		OnlineUser onlineUser = findFirst(sql);
		if(onlineUser == null){
			LOG.warn("用户授权令牌已过期，处理对应在线用户信息时 onlineUser查询不存在 可能已被删除");
			return;
		}
		boolean success = onlineUser.delete();
		if(!success){
			LOG.warn("用户授权令牌已过期，处理对应在线用户信息删除失败");
		}
	}
}
